local global = _G

module "box2d"

local body_mt = {}
body_mt.__index = body_mt

function body_mt:add_circle(x, y, radius)
	local id = body_add_circle(self[2], self[1], x, y, radius)
	return id
end

function body_mt:add_box(x, y, w, h)
	local id = body_add_box(self[2], self[1], x, y, w, h)
	return id
end

function body_mt:pos()
	return body_pos(self[2], self[1])
end

function body_mt:orientation()
	return body_orientation(self[2], self[1])
end

local function world_create_body_(self, x, y, is_static)
	local id = create_body(self[1], x, y, is_static)

	local body = global.setmetatable({id, self[1], self}, body_mt)
	self.id_to_body[id] = body
	return body
end

local function world_step_(self, time_step)
	world_step(self[1], time_step)
end

local function world_destroy_(self)
	world_destroy(self[1])
end

local prev_create_world = create_world

function create_world(other)
	local w
	if not other then
		w = {prev_create_world()}
		w.id_to_body = {} -- Mapping ID to body objects
	else
		w = {clone_world(other[1])}
		w.id_to_body = {} -- Mapping ID to body objects
		for id,v in global.pairs(other.id_to_body) do
			w.id_to_body[id] = global.setmetatable({id, w[1], w}, body_mt)
		end

		--[[ TODO: Bodies as userdata:
			* Cloning:
				* C cloner needs to fill mapping table as well as lua body list. To do this
				  it needs the current body list.
			* Returning from functions:
				* ID to body userdata mapping could be used.

			* Avoiding validation hash table:
				* Need a way to invalidate the userdata. This could be done by keeping pointers
				  in the world. __gc of the userdata can remove the pointer in the world. World
				  destruction can zero out the world reference.
		]]
	end

	w.create_body = world_create_body_
	w.step = world_step_
	w.destroy = world_destroy_
	w.clone = create_world_

	return w
end